package com.google.api.adwords.starterkit.Synchronizer;

import java.rmi.RemoteException;
import java.sql.Connection;
import java.util.HashMap;
import java.util.HashSet;

import javax.xml.rpc.ServiceException;

import org.apache.log4j.Logger;

import com.google.api.adwords.starterkit.db.structures.GeoTargetStructure;
import com.google.api.adwords.starterkit.db.structures.LanguageTargetStructure;
import com.google.api.adwords.starterkit.db.structures.PlatformStructure;
import com.google.api.adwords.starterkit.db.tables.CampaignTable;
import com.google.api.adwords.starterkit.db.tables.GeoTargetTable;
import com.google.api.adwords.starterkit.db.tables.LanguageTargetTable;
import com.google.api.adwords.starterkit.db.tables.PlatformTargetTable;
import com.google.api.adwords.starterkit.settings.StarterKitSettings;
import com.google.api.adwords.starterkit.utils.DumpExceptions;
import com.google.api.adwords.starterkit.utils.ServiceUtils;
import com.google.api.adwords.v201101.cm.ApiException;
import com.google.api.adwords.v201101.cm.CampaignTargetOperation;
import com.google.api.adwords.v201101.cm.CampaignTargetPage;
import com.google.api.adwords.v201101.cm.CampaignTargetSelector;
import com.google.api.adwords.v201101.cm.CampaignTargetServiceInterface;
import com.google.api.adwords.v201101.cm.CityTarget;
import com.google.api.adwords.v201101.cm.CountryTarget;
import com.google.api.adwords.v201101.cm.GeoTarget;
import com.google.api.adwords.v201101.cm.GeoTargetList;
import com.google.api.adwords.v201101.cm.LanguageTarget;
import com.google.api.adwords.v201101.cm.LanguageTargetList;
import com.google.api.adwords.v201101.cm.PlatformTarget;
import com.google.api.adwords.v201101.cm.PlatformTargetList;
import com.google.api.adwords.v201101.cm.ProvinceTarget;
import com.google.api.adwords.v201101.cm.TargetList;

/**
 * The Class TargetsSynchronizer is responsible to load all Targets 
 * information from AdWords system synchronized into local DB.
 * 
 * @author rodrigo.f.vale@gmail.com (Rodrigo Vale)
 */
public class TargetsSynchronizer {
  private ServiceUtils serviceUtils;
  protected GeoTargetTable geoTargetTable;
  protected CampaignTable campaignTable;
  protected LanguageTargetTable languageTargetTable;
  protected PlatformTargetTable platformTargetTable;
  protected static final Logger log = Logger.getLogger("StarterKit");

  public TargetsSynchronizer(StarterKitSettings starterKitSetting, 
      Connection conn) {
    setServiceUtils(new ServiceUtils(starterKitSetting));

    campaignTable = new CampaignTable(conn);
    geoTargetTable = new GeoTargetTable(conn);
    platformTargetTable = new PlatformTargetTable(conn);
    geoTargetTable = new GeoTargetTable(conn);
    languageTargetTable = new LanguageTargetTable(conn);
  }  
  
  public void processOperations(
      HashSet<CampaignTargetOperation> campaignTargetOperation) {
    if (campaignTargetOperation.size() > 0) {
      CampaignTargetOperation[] operations = campaignTargetOperation
          .toArray(new CampaignTargetOperation[campaignTargetOperation.size()]);
      CampaignTargetServiceInterface campaignTargetService;
      try {
        campaignTargetService = getServiceUtils().getCampaignTargetService();
        campaignTargetService.mutate(operations);  
        log.debug("Updated " + operations.length + " CampaignTargets");
      } catch (ServiceException e) {
        DumpExceptions.dumpServiceException(e);
      } catch (ApiException e) {
        DumpExceptions.dumpApiException(e);
      } catch (RemoteException e) {
        DumpExceptions.dumpRemoteException(e);
      }
    }
  }
  
  public ServiceUtils getServiceUtils() {
    return serviceUtils;
  }

  public void setServiceUtils(ServiceUtils serviceUtils) {
    this.serviceUtils = serviceUtils;
  }

  /**
   * Load targets from ad words.
   */
  public void get() {
    log.debug("Processing Targets JSON Objects");
    // Get the CampaignService.
    CampaignTargetServiceInterface targetService;
    HashMap<Long, Integer> campaignsIdsMap 
        = campaignTable.getCampaignId2LocalId();
  
    try {
      targetService = getServiceUtils().getCampaignTargetService();
  
      HashMap<Long, Integer> campaignsMapsIds = campaignTable
          .getCampaignId2LocalId();
      Long[] campaignsIds = campaignsMapsIds.keySet().toArray(new Long[0]);
      long[] lCampaignsIds = new long[campaignsIds.length];
      for (int i = 0; i < campaignsIds.length; i++) {
        lCampaignsIds[i] = campaignsIds[i];
      }
  
      // Create selector.
      CampaignTargetSelector selector = new CampaignTargetSelector();
      selector.setCampaignIds(lCampaignsIds);
  
      // Get selected campaigns.
      CampaignTargetPage page = targetService.get(selector);
  
      // Display campaigns.
      if (page.getEntries() != null) {
        for (TargetList targetList : page.getEntries()) {
          if (targetList instanceof LanguageTargetList) {
            LanguageTargetList languageTargetList 
                = (LanguageTargetList) targetList;
  
            if (languageTargetList.getTargets() != null) {
              for (LanguageTarget languageTarget : languageTargetList
                  .getTargets()) {
                int localCampaignId = campaignsIdsMap
                    .get(languageTargetList.getCampaignId());
                LanguageTargetStructure languageTargetStructure 
                    = new LanguageTargetStructure(localCampaignId, 
                    languageTargetList.getCampaignId(), 
                    languageTarget.getLanguageCode());
                languageTargetTable.saveBatch(languageTargetStructure);
              }
            }
          } else if (targetList instanceof PlatformTargetList) {
            PlatformTargetList platformTargetList 
                = (PlatformTargetList) targetList;
            if (platformTargetList.getTargets() != null) {
              for (PlatformTarget platformTarget : platformTargetList
                  .getTargets()) {
                int localCampaignId = campaignsIdsMap
                    .get(platformTargetList.getCampaignId());                
                PlatformStructure platformStructure 
                    = new PlatformStructure(localCampaignId, 
                        platformTargetList.getCampaignId(), 
                        platformTarget.getPlatformType().getValue());
                platformTargetTable.saveBatch(platformStructure);
              }
            }
          } else if (targetList instanceof GeoTargetList) {
            GeoTargetList geoTargetList = (GeoTargetList) targetList;
  
            if (geoTargetList.getTargets() != null) {
              for (GeoTarget geoTarget : geoTargetList.getTargets()) {
                if (geoTarget instanceof CountryTarget) {
                  CountryTarget countryTarget = (CountryTarget) geoTarget;
                  if (countryTarget.getCountryCode().length() > 0) {
                    
                    GeoTargetStructure geoTargetStructure 
                        = new GeoTargetStructure(
                            campaignsIdsMap.get(geoTargetList.getCampaignId()), 
                            geoTargetList.getCampaignId(), "", "", 
                            countryTarget.getCountryCode(), 
                            countryTarget.getExcluded());
                    geoTargetTable.saveBatch(geoTargetStructure);
                  }
                }
                if (geoTarget instanceof CityTarget) {
                  CityTarget cityTarget = (CityTarget) geoTarget;
  
                  GeoTargetStructure geoTargetStructure 
                      = new GeoTargetStructure(
                          campaignsIdsMap.get(geoTargetList.getCampaignId()), 
                          geoTargetList.getCampaignId(), 
                          cityTarget.getCityName(), 
                          cityTarget.getProvinceCode(), 
                          cityTarget.getCountryCode(), 
                          cityTarget.getExcluded());
                  geoTargetTable.saveBatch(geoTargetStructure);
                }
                if (geoTarget instanceof ProvinceTarget) {
                  ProvinceTarget provinceTarget = (ProvinceTarget) geoTarget;
  
                  GeoTargetStructure geoTargetStructure 
                      = new GeoTargetStructure(
                          campaignsIdsMap.get(geoTargetList.getCampaignId()), 
                          geoTargetList.getCampaignId(), "", 
                          provinceTarget.getProvinceCode(), "", 
                          provinceTarget.getExcluded());
                  geoTargetTable.saveBatch(geoTargetStructure);
                }
              }
            }
          }
        }
        languageTargetTable.executeBatch();
        platformTargetTable.executeBatch();
        geoTargetTable.executeBatch();
      }
    } catch (ServiceException e) {
      DumpExceptions.dumpServiceException(e);
    } catch (ApiException e) {
      DumpExceptions.dumpApiException(e);
    } catch (RemoteException e) {
      DumpExceptions.dumpRemoteException(e);
    }
    campaignTable.resetGeoTargetFlags();
    campaignTable.resetLanguageTargetFlags();
    campaignTable.resetNetworkTargetFlags();
    campaignTable.resetPlatformTargetFlags();
  }
}
